#define FLASH_FID                           (8UL << 6 | 12UL)       /* Definition for mtl_Log() */
/***********************************************************************************************
* DISCLAIMER
************************************************************************************************/
/*""FILE COMMENT""******************************************************************************
 * System Name  : FLASH driver software
 * File Name    : w25q_io.c
 * Version      : 
 * Contents     : FLASH driver I/O module
 * Customer     : Standard
 * Model        : None
 * CPU          : 
 * Compiler     : 
 *              : 
 * OS           : ---
 * Programmer   : 
 * Note         : 
 ***********************************************************************************************
 * History      : Date          Author          Comment
 *""FILE COMMENT END""**************************************************************************/

//#pragma   SFR             /* for 78K0R                                                        */  /** SET **/ 

//#include "mtl_com.h"                                    /* Renesas tool common definitions      */
#include "w25q.h"                           /* FLASH driver common definitions      */
#include "w25q_io.h"                        /* FLASH driver I/O module definitions  */


/************************************************************************************************/
/*  Definitions                                                                                 */
/************************************************************************************************/
#define FLASH_SHORT_SIZE (uint32_t)0x0000fff0

/*---------- Definitions of FLASH command -----------*/
#define FLASH_CMD_WREN      (uint8_t)0x06               /* Write Enable                         */
#define FLASH_CMD_WRDI      (uint8_t)0x04               /* Write Disable                        */
#define FLASH_CMD_RDSR      (uint8_t)0x05               /* Read Status Register                 */
#define FLASH_CMD_WRSR      (uint8_t)0x01               /* Write Status Register                */
#ifdef FLASH_0B_READ_SELECT
#define FLASH_CMD_READ      (uint8_t)0x0b               /* Read for Memory Array                */
#else
#define FLASH_CMD_READ      (uint8_t)0x03               /* Read for Memory Array                */
#endif
#define FLASH_CMD_WRITE     (uint8_t)0x02               /* Write for Memory Array               */
#define FLASH_CMD_SE        (uint8_t)0xd8               /* S_Erase for Memory Array             */
#define FLASH_CMD_BE        (uint8_t)0xc7               /* B_Erase for Memory Array             */
#define FLASH_CMD_DP        (uint8_t)0xb9               /* Deep Power Down                      */
#define FLASH_CMD_RES       (uint8_t)0xab               /* Release Deep Power Down              */
#define FLASH_CMD_RDID      (uint8_t)0x9f               /* Read identification                  */


/************************************************************************************************/
/*  Unions                                                                                      */
/************************************************************************************************/
/* uint16_t <-> uint8_t conversion */
typedef union {
    uint32_t    ul;
    uint8_t uc[4];
} FLASH_EXCHG_LONG;                                     /* total 4byte                          */


/************************************************************************************************/
/*  Structs                                                                                     */
/************************************************************************************************/
/* Definition of FLASH command structure */


/************************************************************************************************/
/*  Globals                                                                                     */
/************************************************************************************************/
/*""VAL DEF""*/
STATIC uint8_t      gFlash_CmdBuf[5];                   /* Command transmission buffer          */

/*""VAL DEF END""*/


/************************************************************************************************/
/*  Macros                                                                                      */
/************************************************************************************************/
/*--------- Command transmission processing ----------*/
/*                                                          Cmd             Addr                CmdSize     */
#define SPI_FLASH_Cmd_WREN()      SPI_FLASH_Send_Cmd(FLASH_CMD_WREN,    (uint32_t)0,    FLASH_CMD_SIZE)
#define SPI_FLASH_Cmd_WRDI()      SPI_FLASH_Send_Cmd(FLASH_CMD_WRDI,    (uint32_t)0,    FLASH_CMD_SIZE)
#define SPI_FLASH_Cmd_RDSR()      SPI_FLASH_Send_Cmd(FLASH_CMD_RDSR,    (uint32_t)0,    FLASH_CMD_SIZE)
#define SPI_FLASH_Cmd_WRSR()      SPI_FLASH_Send_Cmd(FLASH_CMD_WRSR,    (uint32_t)0,    FLASH_CMD_SIZE)
#ifdef FLASH_0B_READ_SELECT
#define SPI_FLASH_Cmd_READ(Addr)  SPI_FLASH_Send_Cmd(FLASH_CMD_READ,    (uint32_t)Addr, FLASH_CMD_SIZE+FLASH_ADDR_SIZE+1)
#else
#define SPI_FLASH_Cmd_READ(Addr)  SPI_FLASH_Send_Cmd(FLASH_CMD_READ,    (uint32_t)Addr, FLASH_CMD_SIZE+FLASH_ADDR_SIZE)
#endif
#define SPI_FLASH_Cmd_WRITE(Addr) SPI_FLASH_Send_Cmd(FLASH_CMD_WRITE,   (uint32_t)Addr, FLASH_CMD_SIZE+FLASH_ADDR_SIZE)
#define SPI_FLASH_Cmd_BE()        SPI_FLASH_Send_Cmd(FLASH_CMD_BE,      (uint32_t)0,    FLASH_CMD_SIZE)
#define SPI_FLASH_Cmd_SE(Addr)    SPI_FLASH_Send_Cmd(FLASH_CMD_SE,      (uint32_t)Addr, FLASH_CMD_SIZE+FLASH_ADDR_SIZE)
#define SPI_FLASH_Cmd_DP()        SPI_FLASH_Send_Cmd(FLASH_CMD_DP,      (uint32_t)0,    FLASH_CMD_SIZE)
#define SPI_FLASH_Cmd_RES()       SPI_FLASH_Send_Cmd(FLASH_CMD_RES,     (uint32_t)0,    FLASH_CMD_SIZE+FLASH_ADDR_SIZE)
#define SPI_FLASH_Cmd_RDID()      SPI_FLASH_Send_Cmd(FLASH_CMD_RDID,    (uint32_t)0,    FLASH_CMD_SIZE)


/************************************************************************************************/
/*  Prototypes                                                                                  */
/************************************************************************************************/
STATIC error_t SPI_FLASH_Write_En(uint8_t DevNo);
STATIC error_t SPI_FLASH_Write_Di(uint8_t DevNo);
STATIC error_t SPI_FLASH_Wait_Busy(uint8_t DevNo, uint16_t BusyTime, uint16_t BusyCnt);
STATIC error_t SPI_FLASH_Send_Cmd(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize);
STATIC void SPI_FLASH_Cmd_set(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize);

/*----------------------------------------------------------------------------------------------*/
/* Port control processing                                                                      */
/*----------------------------------------------------------------------------------------------*/
/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Port initialization processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : void SPI_FLASH_Init_Port(uint8_t DevNo)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Initializes the ports related to the specified device.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *-----------------------------------------------------------------------------------------------
 * Return values: None
 *-----------------------------------------------------------------------------------------------
 * Notes        : Common ports (DataOut, DataIn, and CLK) for all devices are forcibly initialized.
 *""FUNC COMMENT END""***************************************************************************/
void SPI_FLASH_Init_Port(uint8_t DevNo)
{
    FLASH_CS_INIT(DevNo);                           /* CS   "H" /   Output                      */
}


/*----------------------------------------------------------------------------------------------*/
/* Command transmission processing                                                              */
/*----------------------------------------------------------------------------------------------*/
/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Command issuance processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : STATIC error_t SPI_FLASH_Send_Cmd(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Issues a command.
 *              : Generates a transmit command and issues it.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           Cmd                 ;   Command data
 *              : uint32_t          Addr                ;   Address data
 *              : uint8_t           CmdSize             ;   Command size
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the acquisition result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
STATIC error_t SPI_FLASH_Send_Cmd(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize)
{
    error_t             Ret;

    SPI_FLASH_Cmd_set(Cmd, Addr, CmdSize);
    
    /* Command transmission */
    Ret = SIO_Tx_Data((uint16_t)CmdSize, (uint8_t FAR*)&gFlash_CmdBuf);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }
    
    return Ret;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Write enable processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : STATIC error_t SPI_FLASH_Write_En(uint8_t DevNo)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Makes a setting to enable write operations.
 *              : Issues the WREN command and sets the WEL bit.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
STATIC error_t SPI_FLASH_Write_En(uint8_t DevNo)
{
    error_t             Ret;

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Writing enable command transmission */
    Ret = SPI_FLASH_Cmd_WREN();
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    }

    return Ret;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Write disable processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : STATIC error_t SPI_FLASH_Write_Di(uint8_t DevNo)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Makes a setting to disable write operations.
 *              : Issues the WRDI command and resets the WEL bit.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
STATIC error_t SPI_FLASH_Write_Di(uint8_t DevNo)
{
    error_t             Ret;

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Writing disable command transmission */
    Ret = SPI_FLASH_Cmd_WRDI();
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    }

    return Ret;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Status register read processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_Read_StsReg(uint8_t DevNo, uint8_t FAR* pStsReg)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Reads from the status register and checks the read data.
 *              : 
 *              : The following information is stored in the read status storage buffer
 *              : (pStsReg).
 *              :       Bit 7:SRWD
 *              :                 1: BP2, BP1, BP0 are read-only bits
 *              :                 0: BP2, BP1, BP0 are read/writable
 *              :       Bits 6 to 5:Reserved (All "0")
 *              :       Bits 4 to 2:BP2, BP1, BP0
 *              :       Bit 1:WEL
 *              :                 1: Internal Write Enable Latch is set
 *              :                 0: Internal Write Enable Latch is reset
 *              :       Bit 0:WIP
 *              :                 1: Program or Erase cycle is in progress
 *              :                 0: No Program or Erase cycle is in progress
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint8_t FAR*      pStsReg             ;   Read status storage buffer
 *-----------------------------------------------------------------------------------------------
* Return values : Returns the status register acquisition result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : Refer the specification of use Flash about relation between block
 *              : protection bits(BP0,BP1 and BP2) and protection area.
 *              : The information of BP2 bit isn't output from the Flash which status
 *              : register doesn't include of BP2 bit.
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_Read_StsReg(uint8_t DevNo, uint8_t FAR* pStsReg)
{
    error_t             Ret;

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Read status register command transmission */
    Ret = SPI_FLASH_Cmd_RDSR();
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    mtl_wait_lp(FLASH_T_R_ACCESS);

    /* Status register reading */
    Ret = SIO_Rx_Data(FLASH_STSREG_SIZE, pStsReg);
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    return FLASH_OK;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Status register write processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_Write_StsReg(uint8_t DevNo, uint8_t FAR* pStsReg)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Writes to the status register.
 *              : 
 *              : Store the following information in the write status storage buffer
 *              : (pStsReg).
 *              :       Bit 7:SRWD
 *              :               0:Status register can be changed
 *              :               1:Status register cannot be changed
 *              :       Bits 6 to 5:Reserved (All "0")
 *              :       Bits 4 to 2:BP2, BP1, BP0
 *              :       Bits 1, 0:Read-only (All "0")
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint8_t FAR*      pStsReg             ;   Write status storage buffer
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the status register acquisition result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : Refer the specification of use Flash about relation between block
 *              : protection bits(BP0,BP1 and BP2) and protection area.
 *              : The information of BP2 bit can't be written to the Flash which status
 *              : register doesn't include of BP2 bit.
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_Write_StsReg(uint8_t DevNo, uint8_t FAR* pStsReg)
{
#ifdef FLASH_WEL_CHK
    uint8_t             StsReg;                         /* Status buffer                        */
#endif  /* #ifdef FLASH_WEL_CHK */
    error_t             Ret;

    /* Write status fixed data setting */
    *pStsReg = *pStsReg & (uint8_t)0x9C;

    /* Writing enable(WEL set) */
    Ret = SPI_FLASH_Write_En(DevNo);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

#ifdef FLASH_WEL_CHK
    /* Status register reading */
    Ret = SPI_FLASH_Read_StsReg(DevNo, (uint8_t FAR*)&StsReg);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }
    if ((StsReg & FLASH_REG_WEL) == 0x00) {             /* Writing disable                      */
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return FLASH_ERR_OTHER;
    }
#endif  /* #ifdef FLASH_WEL_CHK */

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Write status register command transmission */
    Ret = SPI_FLASH_Cmd_WRSR();
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    /* Status register writing */
    Ret = SIO_Tx_Data(FLASH_STSREG_SIZE, pStsReg);
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    /* Write busy completion waiting */
    Ret = SPI_FLASH_Wait_Busy(DevNo, FLASH_T_WBUSY_WAIT, FLASH_WBUSY_WAIT);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    return FLASH_OK;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Busy completion wait processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : STATIC error_t SPI_FLASH_Wait_Busy(uint8_t DevNo, uint16_t BusyTime, uint16_t BusyCnt)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Waits for write busy to be cancelled.
 *              : (1)BusyCnt =0
 *              :    Reads the status register and waits for busy to be cancelled.
 *              : (2)BusyCnt !=0
 *              :    Reads the status register and waits for up to the BusyCnt 
 *              :    period for busy to be cancelled.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint16_t          BusyTime            ;   Busy wait time
 *              : uint16_t          BusyCnt             ;   Repeat count number of busy check
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the  result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
STATIC error_t SPI_FLASH_Wait_Busy(uint8_t DevNo, uint16_t BusyTime, uint16_t BusyCnt)
{
    uint8_t             RxBuf;                          /* Receive temp buffer                  */
    error_t             Ret;
    
    if (BusyCnt == 0) {

        while (1) {
            Ret = SPI_FLASH_Read_StsReg(DevNo, (uint8_t FAR*)&RxBuf);
                                                        /* Status register reading              */
            if (Ret >= FLASH_OK) {
                /* Ready/Busy chack */
                if ((RxBuf & FLASH_REG_WIP) == 0x00) {  /* Ready ?                              */
                    /* Ready */
                    return FLASH_OK;
                }
            }
            mtl_wait_lp(BusyTime);
        }
    }

    else {
        uint16_t                WaitCnt;                /* Wait counter                         */

        for (WaitCnt = BusyCnt; WaitCnt != 0; WaitCnt--) {
            Ret = SPI_FLASH_Read_StsReg(DevNo, (uint8_t FAR*)&RxBuf);
                                                        /* Status register reading              */
            if (Ret >= FLASH_OK) {
                /* Ready/Busy chack */
                if ((RxBuf & FLASH_REG_WIP) == 0x00) {  /* Ready ?                              */
                    /* Ready */
                    return FLASH_OK;
                }
            }
            mtl_wait_lp(BusyTime);
        }
    }

    /* Busy */
    mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    return FLASH_ERR_HARD;

}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : 1-page write processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_Write_Page(uint8_t DevNo, uint32_t WAddr, uint16_t WCnt,
                :                        uint8_t FAR* pData)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Writes data to Flash in bytes.
 *              : Writes data from the specified address for the specified number of bytes.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint32_t          WAddr               ;   Write start address
 *              : uint16_t          WCnt                ;   Number of bytes to be written
 *              : uint8_t FAR*      pData               ;   Write data storage buffer pointer
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the write result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : A write exceeding the write page isn't allowed.
 *              ; Data can't be written to protected pages and error result isn't returned. 
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_Write_Page(uint8_t DevNo, uint32_t WAddr, uint16_t WCnt, uint8_t FAR* pData)
{
#ifdef FLASH_WEL_CHK
    uint8_t             StsReg;                         /* Status buffer                        */
#endif  /* #ifdef FLASH_WEL_CHK */
    error_t             Ret;

    /* Writing enable(WEL set) */
    Ret = SPI_FLASH_Write_En(DevNo);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

#ifdef FLASH_WEL_CHK
    /* Status register reading */
    Ret = SPI_FLASH_Read_StsReg(DevNo, (uint8_t FAR*)&StsReg);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }
    if ((StsReg & FLASH_REG_WEL) == 0x00) {             /* Writing disable                      */
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return FLASH_ERR_OTHER;
    }
#endif  /* #ifdef FLASH_WEL_CHK */

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Page program command transmission */
    Ret = SPI_FLASH_Cmd_WRITE(WAddr);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    /* Data writing */
#ifndef SIO_DMA_USED
    Ret = SIO_Tx_Data(WCnt, pData);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

#else   /* #ifndef SIO_DMA_USED */
    if (WCnt <= FLASH_BYTE_WRITE) {
        Ret = SIO_Tx_Data(WCnt, pData);
        if (Ret < FLASH_OK) {
            mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
            return Ret;
        }
    } else {
        Ret = SIO_Tx_Data_DMA(WCnt, pData);
        if (Ret < FLASH_OK) {
            mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
            return Ret;
        }
    }
#endif  /* #ifndef SIO_DMA_USED */

    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    
    /* Write busy completion waiting */
    Ret = SPI_FLASH_Wait_Busy(DevNo, FLASH_T_WBUSY_WAIT, FLASH_WBUSY_WAIT);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    return FLASH_OK;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Data read processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_Read_Memory(uint8_t DevNo, uint32_t RAddr, uint32_t RCnt, uint8_t FAR* pData)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Reads data from Flash in bytes.
 *              : Reads data from the specified address for the specified number of bytes.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint32_t          RAddr               ;   Read start address
 *              : uint32_t          RCnt                ;   Number of bytes to be read
 *              : uint8_t FAR*      pData               ;   Read data storage buffer pointer
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the read result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : The maximum read address is Flash size - 1.
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_Read_Memory(uint8_t DevNo, uint32_t RAddr, uint32_t RCnt, uint8_t FAR* pData)
{
    error_t             Ret;
    uint16_t            Cnt;

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Read command transmission */
    Ret = SPI_FLASH_Cmd_READ(RAddr);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    mtl_wait_lp(FLASH_T_R_ACCESS);

    do {
        
        if(RCnt >= FLASH_SHORT_SIZE){
            Cnt = (uint16_t)FLASH_SHORT_SIZE;
        }
        else{
            Cnt = (uint16_t)RCnt;
        }
            
        /* Data reading */
#if (!defined(SIO_DMA_USED) || defined(SIO_RRM_UNUSED))
        Ret = SIO_Rx_Data(Cnt, pData);
        if (Ret < FLASH_OK) {
            mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
            return Ret;
        }

#else   /* #if (!defined(SIO_DMA_USED) || defined(SIO_RRM_UNUSED)) */
        if (RCnt <= FLASH_BYTE_READ) {
            Ret = SIO_Rx_Data(Cnt, pData);
            if (Ret < FLASH_OK) {
                mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
                return Ret;
            }
        } else {
            Ret = SIO_Rx_Data_DMA(Cnt, pData);
            if (Ret < FLASH_OK) {
                mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
                return Ret;
            }
        }
#endif  /* #if (!defined(SIO_DMA_USED) || defined(SIO_RRM_UNUSED)) */

        pData   +=  Cnt;
        RCnt    -=  Cnt;
    }while(RCnt != 0);

    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */

    return FLASH_OK;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Erase processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_Erase(uint8_t DevNo, uint32_t EAddr, uint8_t Etype)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Bulk Erase        ; All data of Flash are erased.
 *              : Sector Erase      ; Sector data of erase address are erased.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *              : uint32_t          EAddr               ;   Erase address
 *              : uint8_t           Etype               ;   Type of erase command
 *              :                                           FLASH_B_ERASE ; Bulk Erase
 *              :                                           FLASH_S_ERASE ; Sector Erase
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the erase result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : Flash can be erased to only when write-protection has been canceled.
 *              : (1)Bulk Erase
 *              :   Data can't be erased and error result isn't returned when Flash is
 *              :   write protected.
 *              : (2)Sector Erase
 *              :   Data of protected sector can't be erased and error result isn't returned.
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_Erase(uint8_t DevNo, uint32_t EAddr, uint8_t Etype)
{
#ifdef FLASH_WEL_CHK
    uint8_t             StsReg;                         /* Status buffer                        */
#endif  /* #ifdef FLASH_WEL_CHK */
    error_t             Ret;

    /* Writing enable(WEL set) */
    Ret = SPI_FLASH_Write_En(DevNo);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

#ifdef FLASH_WEL_CHK
    /* Status register reading */
    Ret = SPI_FLASH_Read_StsReg(DevNo, (uint8_t FAR*)&StsReg);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }
    if ((StsReg & FLASH_REG_WEL) == 0x00) {             /* Writing disable                      */
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return FLASH_ERR_OTHER;
    }
#endif  /* #ifdef FLASH_WEL_CHK */

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* Erase command transmission */
    if(Etype==FLASH_B_ERASE){
        Ret = SPI_FLASH_Cmd_BE();                     /*Bulk erase                            */
    }
    else{
        Ret = SPI_FLASH_Cmd_SE(EAddr);                /*Sector erase                          */
    }
    
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    /* Erase busy completion waiting */
    Ret = SPI_FLASH_Wait_Busy(DevNo, FLASH_T_EBUSY_WAIT, FLASH_EBUSY_WAIT);
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    return FLASH_OK;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Deep power down processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_DPD(uint8_t DevNo)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Set the deep power down mode.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the deep power down result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_DPD(uint8_t DevNo)
{
    error_t             Ret;
    
    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* DP command transmission */
    Ret = SPI_FLASH_Cmd_DP();
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    }
    
    return Ret;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : Release deep power down processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_ReleaseDPD(uint8_t DevNo, uint8_t FAR* pData)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Change mode from deep power down to standby.
 *              : Read electronic signature.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           DevNo               ;   Device number
 * Arguments    : uint8_t FAR*      pData               ;   Electronic signature storage buffer pointer
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the release deep power down result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_ReleaseDPD(uint8_t DevNo, uint8_t FAR* pData)
{
    error_t             Ret;

    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* RES command transmission */
    Ret = SPI_FLASH_Cmd_RES();
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    mtl_wait_lp(FLASH_T_R_ACCESS);

    /* Electronic Signature reading */
    Ret = SIO_Rx_Data(FLASH_ESIG_SIZE, pData);        /* 1byte is read for speed-up           */
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    }

    return Ret;
}


/*""FUNC COMMENT""*******************************************************************************
 * Outline      : ID read processing
 *-----------------------------------------------------------------------------------------------
 * Declaration  : error_t SPI_FLASH_ID(uint8_t DevNo, uint8_t FAR* pData)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Read Manufacture ID and Device ID.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t FAR*  pData                   ;   ID data storage buffer pointer
 *              : ID data of 3 bytes are stored in the following order.
 *              :                               (1) Manufacture ID
 *              :                               (2) Memory type
 *              :                               (3) Memory capacity
 *-----------------------------------------------------------------------------------------------
 * Return values: Returns the ID read result.
 *              : FLASH_OK                              ;   Successful operation
 *              : FLASH_ERR_HARD                        ;   Hardware error
 *              : FLASH_ERR_OTHER                       ;   Other error
 *-----------------------------------------------------------------------------------------------
 * Notes        : None
 *""FUNC COMMENT END""***************************************************************************/
error_t SPI_FLASH_ID(uint8_t DevNo, uint8_t FAR* pData)
{
    error_t             Ret;
    
    FLASH_SET_CS(DevNo, FLASH_LOW);                     /* CS "L"                               */
    mtl_wait_lp(FLASH_T_CS_HOLD);

    /* RDID command transmission */
    Ret = SPI_FLASH_Cmd_RDID();
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
        return Ret;
    }

    mtl_wait_lp(FLASH_T_R_ACCESS);

    /* Data reading */
    Ret = SIO_Rx_Data(FLASH_IDDATA_SIZE, pData);
    mtl_wait_lp(FLASH_T_CS_HOLD);
    FLASH_SET_CS(DevNo, FLASH_HI);                      /* CS "H"                               */
    if (Ret < FLASH_OK) {
        mtl_Log(FLASH_LOG_ERR, 0, FLASH_FID, __LINE__);
    }

    return Ret;
}


/*----------------------------------------------------------------------------------------------*/
/* Data conversion processing                                                                   */
/*----------------------------------------------------------------------------------------------*/
/*""FUNC COMMENT""*******************************************************************************
 * Outline      :  Command and address setting.
 *-----------------------------------------------------------------------------------------------
 * Declaration  : void SPI_FLASH_Cmd_set(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize)
 *-----------------------------------------------------------------------------------------------
 * Functions    : Command and address setting. 
 *              : Converts little endian data or big endian data.
 *-----------------------------------------------------------------------------------------------
 * Arguments    : uint8_t           Cmd                 ;   Command data
 *              : uint32_t          Addr                ;   Address data
 *              : uint8_t           CmdSize             ;   Command size
 *-----------------------------------------------------------------------------------------------
 * Return values: None
 *-----------------------------------------------------------------------------------------------
 * Notes        : Switch MTL_MCU_LITTLE in mtl_com.h to match the environment.
 *""FUNC COMMENT END""***************************************************************************/
STATIC void SPI_FLASH_Cmd_set(uint8_t Cmd, uint32_t Addr, uint8_t CmdSize)
{
    FLASH_EXCHG_LONG        Tmp;

    Tmp.ul = Addr;

    if (CmdSize == FLASH_CMD_SIZE) {

        gFlash_CmdBuf[0] = Cmd;

    }else if(CmdSize == 4){
#ifdef MTL_MCU_LITTLE
        gFlash_CmdBuf[0] = Cmd;
        gFlash_CmdBuf[1] = Tmp.uc[2];
        gFlash_CmdBuf[2] = Tmp.uc[1];
        gFlash_CmdBuf[3] = Tmp.uc[0];
#else   /* #ifdef MTL_MCU_LITTLE */
        gFlash_CmdBuf[0] = Cmd;
        gFlash_CmdBuf[1] = Tmp.uc[1];
        gFlash_CmdBuf[2] = Tmp.uc[2];
        gFlash_CmdBuf[3] = Tmp.uc[3];
#endif  /* #ifdef MTL_MCU_LITTLE */

    }else if(CmdSize == 5){
#ifdef MTL_MCU_LITTLE
        gFlash_CmdBuf[0] = Cmd;
        gFlash_CmdBuf[1] = Tmp.uc[2];
        gFlash_CmdBuf[2] = Tmp.uc[1];
        gFlash_CmdBuf[3] = Tmp.uc[0];
        gFlash_CmdBuf[4] = 0xFF;
#else   /* #ifdef MTL_MCU_LITTLE */
        gFlash_CmdBuf[0] = Cmd;
        gFlash_CmdBuf[1] = Tmp.uc[1];
        gFlash_CmdBuf[2] = Tmp.uc[2];
        gFlash_CmdBuf[3] = Tmp.uc[3];
        gFlash_CmdBuf[4] = 0xFF;
#endif  /* #ifdef MTL_MCU_LITTLE */
    }   
}

/* End of File */
